﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Mathematics
{
    public sealed class Variable:MathExpression
    {
        private double? _value;

        internal Variable(string name)
        {
            Name = name;
            IsMutable = true;
            _value = null;
        }

        internal Variable(string name,bool isMutable,double value)
        {
            Name = name;
            IsMutable = isMutable;
            _value = value;
        }

        #region Public Properties

        public double Value {
            get
            {
                if (!_value.HasValue)
                    throw new VariableNotSetException();
                return _value.Value;
            }
           
        }

        public bool IsMutable { get; private set; }
        public string Name { get; private set; }
        public bool IsSet { get { return _value.HasValue; } }
        public bool IsAssigned { get; internal set; }

        #endregion

        #region Public Methods

        public void Set(double value)
        {
            if (!IsMutable)
                throw new ImmutableVariableException("Constant Variables may not be modified once set.");
            _value = value;
        }

        public override string ToString()
        {
            return Name;
        }

        public override double? Evaluate()
        {
            if (IsSet)
                return Value;
            throw new UnableToEvaluateException();
        }

        protected internal override MathExpression Reduce(out bool didReduce)
        {
            if (IsSet)
            {
                didReduce = true;
                return new Constant(Value);
            }
            else
            {
                didReduce = false;
                return this;
            }
        }

        public override bool CanEvaluate()
        {
            return IsSet;
        }

        //public override IEnumerable<Variable> GetVariables()
        //{
        //    yield return this;
        //}

        //public override IEnumerable<Constant> GetConstants()
        //{
        //    return new Constant[0];
        //}

        #endregion

        #region Static Methods



        #endregion
    }
}
